#include "RootMinimizer.h"

using namespace ROOT::Minuit2;

bool RootMinimizer::Min(const MATHLIB::matrix33& a_surf,
		const MATHLIB::matrix33& a_tool)
{
	m_miniFun.Init(a_surf, a_tool);

	std::vector<double> par, err;
	par.resize(2);
	err.resize(2, 0.1);
	par[0] = m_a;
	par[1] = m_b;

	//MnUserParameters upar(par, err);
	//upar.SetLowerLimit(0, 0.0);
	//upar.SetLowerLimit(1, 0.0);
	//std::string a_name = "A";
	//std::string b_name = "B";

	//upar.Add(a_name, m_a, 0.01);
	//upar.Add(b_name, m_b, 0.01);

	//MnMigrad minimizer(m_miniFun, upar);
	//FunctionMinimum mini = minimizer();
	//SimplexMinimizer minimizer;
	VariableMetricMinimizer minimizer;
	FunctionMinimum mini = minimizer.Minimize(m_miniFun ,par, err);
	//MnUserParameters upar(par, err);
	//for(unsigned int k=0; k<par.size(); ++k) 
	//	upar.SetLowerLimit(k, 0.0);
	
	//MnMinimize minimizer(m_miniTool, upar);
	//FunctionMinimum mini = minimizer();
	
	m_a = mini.UserParameters().Value(0);
	m_b = mini.UserParameters().Value(1);
	double mF = mini.Fval();
	////std::cout <<std::endl<< mini <<std::endl;
	return mini.IsValid();
}

bool RootMinimizer::MinTool(const std::list<MATHLIB::vector3>& a_A, const std::list<MYFLOAT>& a_b)
{
	m_miniTool.Init(a_A, a_b);

	std::vector<double> par, err;
	par.resize(a_b.size(), 0.002);
	err.resize(a_b.size(), 0.1);

	MnUserParameters upar(par, err);
	for(unsigned int k=0; k<par.size(); ++k) 
		upar.SetLowerLimit(k, 0.0);
	
	MnMinimize minimizer(m_miniTool, upar);
	//MnSimplex minimizer(m_miniTool, upar);
	
	FunctionMinimum mini = minimizer();
	//for(unsigned int k=0; k<par.size(); ++k) 
	//	minimizer.RemoveLimits(k);
	
	std::list<MATHLIB::vector3>::const_iterator ifirst = a_A.begin();
	m_x = m_y = m_z = 0.0;
	double l;
	for(unsigned int w=0; w<a_b.size() && ifirst != a_A.end(); ++w) {
		l = mini.UserParameters().Value(w);
		//std::cout <<"\nl: "<<l<<std::endl;
		m_x += ifirst->x * l;
		m_y += ifirst->y * l;
		m_z += ifirst->z * l;
		++ifirst;
	}
	m_x *= 0.5;
	m_y *= 0.5;
	m_z *= 0.5;
	double mF = mini.Fval();
	//std::cout <<"\n====> Minimalny dystans:   "<< mF <<std::endl;
	return mini.IsValid();
}